#include <common.h>
#include <vmm.h>
#include <process.h>
#include <thread.h>
unsigned int ps_list;

process *get_process(unsigned int pid)
{
	process_list *i = processes;
	while(i)
	{
		if(i->ps->pid == pid)
			return i->ps;
		i = i->next;
	}
	return 0;
}

void move_stack(void *new_stack_start, unsigned int initial_esp, unsigned int size)
{
	unsigned int i;
	for(i = (unsigned int)new_stack_start; i >= ((unsigned int)new_stack_start-size); i-=0x1000)
	{
		map(i,pmm_alloc_page(), PAGE_PRESENT | PAGE_WRITE | PAGE_USER);
		asm volatile ("invlpg (%0)" : : "a" (i));
	}
	register unsigned int old_stack_pointer asm ("esp");
	register unsigned int old_base_pointer asm ("ebp");	

	unsigned int offset = (unsigned int)new_stack_start - initial_esp;

	unsigned int new_stack_pointer = old_stack_pointer + offset;
	unsigned int new_base_pointer = old_base_pointer + offset;

	memcopy((unsigned char *)new_stack_pointer, (unsigned char *)old_stack_pointer, initial_esp - old_stack_pointer);

	for (i = (unsigned int)new_stack_start; i >  (unsigned int)new_stack_start-size; i -=4)
	{
		unsigned int tmp = *(unsigned int *)i;
		if((old_stack_pointer< tmp) && (tmp < initial_esp))
		{
			tmp = tmp + offset;
			unsigned int *tmp2 = (unsigned int *)i;
			*tmp2 = tmp;
		}
	}

	asm volatile ("mov %0, %%esp" : : "r" (new_stack_pointer));
	asm volatile ("mov %0, %%ebp" : : "r" (new_base_pointer));
}
thread *parent_thread;

void process_add(process *p)
{
	spin(&ps_list);
	process_list *item = (process_list *)kmalloc(sizeof(process_list));

	item->ps = p;
	item->next = processes;
	processes = item;
	ps_list = 0;
}

void process_remove(process *p)
{
spin(&ps_list);
	process_list *i = processes;
	if(i->ps == p)
	{
		processes = i->next;
		kfree(i);
		return;
	}
	while(i->next)
	{
		if(i->next->ps == p)
		{
			process_list *temp = i->next;
			i->next = temp->next;
			kfree(temp);
			return;
		}
		i = i->next;
	}
	ps_list = 0;
}

thread *_fork(registers *regs)
{

	process *parent = current_process;

	process *new_ps = (process *)kmalloc(sizeof(process));
	new_ps->pid = next_pid++;
	new_ps->ppid = parent->pid;

	thread *new = (thread *)new_thread();
	new->tid = next_tid++;
	new->ptid = current_thread->tid;

	memcopy(&new->r,regs,sizeof(registers));

	new_ps->pd = (page_directory_t *)copy_directory(current_directory);

	process_add(new_ps);
	bind_thread(new,new_ps,find_binding(current_thread));
	regs->eax = new_ps->pid;
	new->r.eax = 0;

	return new;
}

void init_processes(unsigned int initial_esp)
{
	next_pid = 1;
	processes = 0;
	kernel_process = (process *)kmalloc(sizeof(process));
	process_add(kernel_process);
	kernel_process->pid = next_pid++;
	kernel_process->ppid = 0;

	page_directory_t *new_pd = (page_directory_t *)copy_directory(current_directory);

	kernel_process->pd = new_pd;

	switch_page_directory(new_pd);

	current_process = kernel_process;
	current_thread->process = current_process;
}
